Scooping and Flashlight-Design Documentation
1.Executive Summary
We implement an interactive, non-destructive 3D “Scooping/Flashlight” tool for vtk.js volume rendering. A fixed-size box moves through a CT volume and makes all voxels inside the box transparent by setting their scalar value to 0. This hides interior regions without permanently modifying data. Current state: translation via a center handle; no rotation handle yet (planned).
2. Scope & Goals
Scooping Viewer: IJK-aligned box built with vtkPlanes; on interaction, restore cached scalars, zero inside-box scalars, re-render.
Flashlight: oriented world-space box (wireframe cue via vtkCubeSource); masking via projection onto the box basis; non-destructive.
Always start from original (cached) scalar data per interaction.
Opacity TF maps 0 → 0 opacity so inside becomes invisible.
3.Architecture Overview
Data Flow (conceptual):
UI/Widget → ScoopingWidget → (restore cached scalars) → mask inside box → vtkImageData(scalars) → vtkVolumeMapper → vtkVolume (render).
vtkCubeSource (wireframe cue) is visual only; it does not crop or mask.
Scooping Viewer — Simple Architecture Flow

4.Data Model & Definitions
Cached Scalars: untouched copy of original voxel intensities (vtkImageData point-data).
Scalar Value: per-voxel intensity consumed by the volume mapper; opacity TF maps intensity to transparency (0 → 0 opacity).
Oriented Box (Flashlight): center C (world), size [sx, sy, sz] (world units), axes [ax, ay, az] (orthonormal).
IJK Box (Scooping): vtkPlanes define axis-aligned bounds in IJK index space.
5.Masking Algorithm (Core)
On each interaction: restore → bound → iterate → project → test → zero → render.
- Restore the scalar array from the cached copy (start from unmodified data).
- Compute an IJK bounding range from the 8 world‑space corners of the active box.
- For each voxel (i, j, k) in that IJK range:
- Convert (i, j, k) → world position p.
- q = p − C (vector from box center).
- Project: lx = dot(q, ax), ly = dot(q, ay), lz = dot(q, az).
- With half‑sizes hx=sx/2, hy=sy/2, hz=sz/2: if |lx|≤hx && |ly|≤hy && |lz|≤hz → INSIDE → set scalar=0.
- Request render; opacity TF maps 0 → 0 opacity so inside voxels become invisible.
Pseudocode — Oriented-Box Masking

Flashlight Implementation — Oriented Box Flow

6.Interaction & UX
Handles: Center handle (translation). Rotation handle: not in V1 (planned).
Highlighting: center handle hover/active; (future) rotation line turns green on pick.
7. Interaction & UX
• Handles: Center handle (translation). Rotation line/axis: NOT implemented in Version1 (planned).
• Highlighting: center handle hover/active; (future) rotation line turns green when picked.
8. Scooping Viewer vs Flashlight — Practical Notes
• Scooping Viewer uses vtkPlanes (IJK‑aligned) to define the box; masking is still done by zeroing inside‑box scalars.
• Flashlight emphasizes an oriented world‑space box; vtkCubeSource is only a wireframe cue. The masking math is identical (basis projection).
• Both approaches are non‑destructive thanks to the cached scalar restore.
9.Roadmap
- Version1 — Translation + masking via scalar=0; IJK‑aligned vtkPlanes; oriented‑box masking core in place.
- Version2 — Add rotation line/axis handle; camera‑axis unlock during rotation; highlight line (green) on pick.